#include "serveur.h"

char *depart="depart";

int        sock_tab    [NCONNS] = { [ 0 ... NCONNS-1 ] = -1 };
pthread_t  pid_tab     [NCONNS] = { [ 0 ... NCONNS-1 ] = -1 };//moyen de pas use ceci
log_client log_clients [NCONNS];

int nsocks = 0;
pthread_mutex_t mutex;



void 
perror_and_exit_whenever(int assertion)
{
  if (assertion)
    {
      perror("appel fonction perror : ");
      exit(EXIT_FAILURE);
    }
}



void *
requete(void * fdc)
{
  int i = (int) fdc;
 
  //int r;
  //  char buffer[BUFFER_SIZE];
  char *path;
  int code_requete = 400;

  // if ((r = read(sock_tab[i],buffer,BUFFER_SIZE)) > 0)
  //{
  char *requete = recupere_requete(sock_tab[i]);
  code_requete = traiter_requete(requete,path,log_clients[i].requete);
  printf("req = %s\n",requete);
      //}

  head(i, "www/truc.html");
 
  if (code_requete == 400)
    {
      log_clients[i].code_retour = malloc(sizeof(char)*(strlen(requete_mauvaise)+1));
      strcpy(log_clients[i].code_retour,requete_mauvaise);
      deconnecter_client(i);
      return NULL;
    }

  

  if (code_requete == 1 || code_requete == 2)
    { 
      //get_page1(i, path);
    }
  //else
  // printf("requete = %d\nfuck !\n",requete);

  if (code_requete ==  3)
    printf("HEAD §!!\n");
  
  
  deconnecter_client(i);
  return NULL;
}

void
deconnecter_client(int indice)
{
  pthread_mutex_lock(&mutex);

  rentrer_log(&log_clients[indice]);
  
  printf("%s deconnecte\n\n",log_clients[indice].nom);
  close(sock_tab[indice]);

  liberer_log(&log_clients[indice]);
  sock_tab[indice] = -1;
  nsocks--;
  //  pthread_kill(pid du main,usr1);
  pthread_mutex_unlock(&mutex);
}

void
liberer_log(log_client *log)
{
  free(log->nom);
  free(log->date_connexion);
  free(log->requete);
  free(log->code_retour);
  free(log->user_agent);
  memset(log,0,sizeof(log_client));
}

void
usage()
{
  fprintf(stderr,"Usage : ./serveur [fonctionnement]\nfonctionnement = thread ou select\n");
  exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
  //TESTER ARGS POUR SAVOIR SI ON UTILISE SELECT OU THREAD §
  if (argc < 2 || (strcmp(argv[1],"thread") != 0 && strcmp (argv[1],"select")))
    usage();


  //open fichier log d'erreurs et rediriger la sortie derreur
  int fderr = open(LOG_ERROR,O_WRONLY | O_CREAT | O_APPEND, 0600);
  if (fderr == -1)
    {
      perror("error log\n");
      exit(1);
    }
  dup2(fderr,2);
  close(fderr);
  


  int sock = socket(AF_INET,SOCK_STREAM,0);
  pthread_mutex_init(&mutex,NULL);
  
  struct sockaddr_in addr;
  socklen_t socklen = sizeof addr;

  struct sockaddr_in sin;
  memset(&sin, 0, sizeof sin);


  
  sin.sin_family = AF_INET;
  sin.sin_port = htons(PORT);

  int b = 1;

  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,&b,sizeof(b));


  if (bind(sock, (struct sockaddr*)&sin,sizeof sin) == -1)
    {
      perror("bind problem\n");
      exit(1);
    }

  if (listen(sock, 1)== -1)
    {
      perror("listen problem\n");
      exit(1);
    }
  
  
  printf("connecte, bind et listen reussis\n");

  if (strcmp(argv[1],"thread")==0)
    {
      while(1)//il faut faire une version avec select
	{      
	  for (int i = 0; i < NCONNS; i++) 

	    {
	      if (sock_tab[i] == -1){//ne pas utiliser sock_tab, juste
		//accept, mais utiliser pause apres
		
		sock_tab[i] = accept(sock,(struct sockaddr*)&addr,&socklen);
		nsocks++;
		
		//	    printf("nouveau client : %s, %s\n",user[i],serv); //getnameinfo(inet_ntoa(addr.sin_addr)));
	    
		init_log(&addr,&log_clients[i]);
	    
		pthread_create(&pid_tab[i],NULL, requete, (void *)i);
		break;
	      }
	    }

	  //pause ici -> faire sigaction() pour debloquer
	}
    }

  else //select
    {

    }

  close(sock);

  return EXIT_SUCCESS;
}



void
get_page(int isock, char *path)
{
  //CE QUI SUIT : IL FAUT FAIRE LES TESTS DE VALIDITE
  // + METTRE A JOUR LES STRUCTURE DE LOG (reponse requete)

  //char *realpath = 


  if (est_dossier(path))
    {
      if (!index_existe(path))
	{
	  char *index =generer_index(path,"index"); 
	  write(isock,index,sizeof(char)*(strlen(index)+1));
	  //faire test pour voir si le write sest bien passe
	  free(index);
	}
      else
	{
	  strcat(path,"index.html");//TESTER SI CEST PAS .HTM
	  int fdindex = open(path,O_RDONLY);
	  copier_fichier(isock,fdindex);
	  close(fdindex);
	}
    }
    
    else //on reclame un fichier
      {
	

      }


}

void
head(int isock, char *path)
{
  printf("head !\n");
  char *head = get_head(path);
  printf("head recupere = %s\n", head);

  int r = write(sock_tab[isock], head, strlen(head)+1);
  
  perror_and_exit_whenever(r <= 0);
}




void 
init_log(struct sockaddr_in* addr,log_client* log)
{
  //initialise qu'une partie des logs, le reste est fait durant le traitement de la requete

  char serv[SERV_SIZE]; 
  char name[BUFFER_SIZE];

  int gn =  getnameinfo((struct sockaddr*)&addr, sizeof addr,
			name, BUFFER_SIZE,
			serv, SERV_SIZE,0);
		
  
  perror_and_exit_whenever(gn == 0);


  time_t t = time(NULL);
  char *date = asctime(localtime(&t));
  
  log->nom = malloc(sizeof(char)*(strlen(name)+1));
  log->date_connexion = malloc(sizeof(char)*(strlen(date)+1));

  strcpy(log->ip,inet_ntoa(addr->sin_addr));
  strcpy(log->nom,name);
  strcpy(log->date_connexion,date);
  


}
  

void
rentrer_log(log_client *log)
{
  FILE* log_file = fopen(LOG_FILE,"a");
  
  perror_and_exit_whenever(!log_file);
  
  fprintf(log_file,"\n%s",log->date_connexion);
  fprintf(log_file,"%s\n",log->ip);
  fprintf(log_file,"%s\n",log->nom);
  fprintf(log_file,"%s\n",log->requete);
  fprintf(log_file,"%s\n",log->code_retour);

  fclose(log_file);

}


void
copier_fichier(int fd_dst,int fd_src)
{
  char buff_copier[BUFFER_SIZE];
  int r_copier;
  while ((r_copier = read(fd_src,buff_copier,BUFFER_SIZE)) > 0)
    if (write(fd_dst,buff_copier,r_copier) <= 0)
      perror_and_exit_whenever(1);
  

}


char *
get_head(char *path)
{
  int fd = open(path,O_RDONLY);
  perror_and_exit_whenever(fd == -1);

  char  buffer[BUFFER_SIZE];
  int   nb_read;

  
  int   size_head = BUFFER_SIZE;
  char *head = malloc(sizeof(char)*size_head);

  int off = 0;

  while ((nb_read = read(fd,buffer, BUFFER_SIZE - 1)) > 0)
    {
      
      if (size_head < off + nb_read)
	{
	  size_head <<= 1;
	  head = realloc(head,sizeof(char)*size_head);
	}


      buffer[nb_read] = '\0';
      strcpy(head + off, buffer);
      off += nb_read;
      
      char *off_bis;
      if ((off_bis = strstr(head,"</head>")) != NULL)
	{
	  head[strlen(head) - strlen(off_bis) + strlen("</head>")] = '\0';
	  break;
	}
            
    }

  close(fd);
  return head;
}

/*
void
get_page1(int isock, char *path)
{
  DIR *dir;
  char realpath[1024] = ROOT;
  strcat(realpath,path);
  printf("realpath = %s\n",realpath);


  if ((dir = opendir(realpath)) != NULL)
    {
      strcat(realpath,"index.html");
      printf("dossier demande !\n");
    }
  
  int fd = open(realpath,O_RDONLY);
  
  if (fd == -1)
    {
      printf("page non ouverte\n");
      if ((strstr(realpath,"index.html")!=NULL  ||
	   strstr(realpath,"index.htm") !=NULL) && errno == ENOENT)
	{
	  int pid;
	  int tube[2];
	  pipe(tube);
	  
	  if ((pid = fork())== 0)
	    {
	      dup2(tube[1],1);
	      close(tube[1]);
	      close(tube[0]);
	      execlp("ls","ls",NULL);
	      perror_and_exit_whenever(1);
	    }

	  else
	    {

	      if (write(sock_tab[isock],requete_ok,sizeof (requete_ok)) <= 0)
		perror_and_exit_whenever(1);

	      strcpy(log_clients[isock].code_retour,requete_ok);  
	      if (write(sock_tab[isock],content,strlen(content)) <= 0)
		perror_and_exit_whenever(1);

	      close(tube[1]);
	            
	      int fheader = open("header.html",O_RDONLY);
	      perror_and_exit_whenever(fheader == -1);

	      copier_fichier(sock_tab[isock],fheader);
	      close(fheader);

	      printf("je debute la copie\n");
	      int rr;
	      char buffr[BUFFER_SIZE];
	      while ((rr = read(tube[0],buffr,BUFFER_SIZE)) > 0)
		//attention a pas couper un mot en deux
		{
		  char buffr2[1024];
		  int offset = 0;
		  while (sscanf(buffr+offset," %s ",buffr2) == 1)
		    {
		      char buffr3[1024];
		      sprintf(buffr3,"<p><A HREF=\"%s\">%s</A></p>",buffr2,buffr2);
		      write(sock_tab[isock],buffr3,strlen(buffr3));
		      		      
		      offset+=strlen(buffr2)+1;
		      buffr2[0]='\0';
		    }
		}

	      int ffooter = open("footer.html",O_RDONLY);
	      perror_and_exit_whenever(ffooter == -1);
	      copier_fichier(sock_tab[isock],ffooter);
	      close(ffooter);

	     

	    }
	  waitpid(pid,NULL,0);
	  return;
	}
      else
	{

	  perror("ouverture");
	  if (write(sock_tab[isock],requete_not_found,strlen(requete_not_found)) <= 0)
	    perror("problème ecriture\n");
	  write(sock_tab[isock],content,strlen(content));
	  strcpy(log_clients[isock].code_retour,requete_not_found); 
	  
	  fd = open("truc.html",O_RDONLY);
	  
	  if (fd == -1)
	    {
	      perror("fichier truc.html non existant\n");
	      exit(1);
	    }
	  
	  printf("copie page not found\n");
	  copier_fichier(sock_tab[isock],fd);
	  close(fd);
	  return;
	}
      
    }
  else
    {
      if (write(sock_tab[isock],requete_ok,sizeof (requete_ok)) <= 0)
	{
	  perror("problème ecriture\n");
	      
	}
      strcpy(log_clients[isock].code_retour,requete_ok);
      copier_fichier(sock_tab[isock],fd);
      close(fd);
    }
  
    }*/



